
(ns ca.uoit.molly.entity-tree
  (:require [clojure.zip :as zip]))


(defn empty-tree []
  (zip/vector-zip [nil]))

(defn node-content [loc]
  (-> loc zip/down zip/node))

(defn node-children [loc]
  (loop [current (-> loc zip/down zip/right)
         children []]
    (if (nil? current)
      children
      (recur (zip/right current) (conj children current)))))

(defn find-child-loc
  [loc v]
  (loop [current (-> loc zip/down zip/right)
         found false
         child nil]
    (if (or (nil? current) found)
      (if found child nil)
      (recur (zip/right current) (= v (node-content current)) current))))

(defn add-child
  "Create a new child under loc, and move to the new child"
  [loc data]
  (-> loc zip/down zip/rightmost (zip/insert-right [data]) zip/rightmost))

(defn graft [loc vein]
  (if (empty? vein)
    (-> loc zip/root zip/vector-zip)
    (let [child (find-child-loc loc (first vein))]
      (if (nil? child)
        (recur (add-child loc (first vein)) (rest vein))
        (recur child (rest vein))))))

(defn build-tree [& veins]
  (loop [veins veins
         t (empty-tree)]
    (if (empty? veins)
      (zip/node t)
      (recur (rest veins) (graft t (first veins))))))

(defn print-tree 
  ([t]
    (print-tree t ""))
  ([n margin]
    (let [content (first n)
          children (rest n)]
      (println margin content)
      (when (not (nil? children))
        (doseq [c children]
          (print-tree c (str margin "  ")))))))
